/*
 * FreeRTOS Kernel V10.2.1
 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */

/*
	BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0.
*/

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"

/* Library includes. */
#include "main.h"

extern UART_HandleTypeDef huart1;
uint8_t aRxBuffer; //缓存
/* Demo application includes. */
#include "serial.h"
/*-----------------------------------------------------------*/

/* Misc defines. */
#define serINVALID_QUEUE ((QueueHandle_t)0)
#define serNO_BLOCK ((TickType_t)0)
#define serTX_BLOCK_TIME (40 / portTICK_PERIOD_MS)

/*-----------------------------------------------------------*/

/* The queue used to hold received characters. */
static QueueHandle_t xRxedChars;
static QueueHandle_t xCharsForTx;

/*-----------------------------------------------------------*/

/* UART interrupt handler. */
void vUARTInterruptHandler(void);

/*-----------------------------------------------------------*/

/*
 * See the serial2.h header file.
 */
xComPortHandle xSerialPortInitMinimal(unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength)
{
	xComPortHandle xReturn;

	/* Create the queues used to hold Rx/Tx characters. */
	xRxedChars = xQueueCreate(uxQueueLength, (unsigned portBASE_TYPE)sizeof(signed char));
	xCharsForTx = xQueueCreate(uxQueueLength + 1, (unsigned portBASE_TYPE)sizeof(signed char));

	/* If the queue/semaphore was created correctly then setup the serial port
	hardware. */
	if ((xRxedChars != serINVALID_QUEUE) && (xCharsForTx != serINVALID_QUEUE))
	{
		HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1); //将开启中断接收
	}
	else
	{
		xReturn = (xComPortHandle)0;
	}

	/* This demo file only supports a single port but we have to return
	something to comply with the standard demo header file. */
	return xReturn;
}
/*-----------------------------------------------------------*/

signed portBASE_TYPE xSerialGetChar(xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime)
{
	/* The port handle is not required as this driver only supports one port. */
	(void)pxPort;

	/* Get the next character from the buffer.  Return false if no characters
	are available, or arrive before xBlockTime expires. */
	if (xQueueReceive(xRxedChars, pcRxedChar, xBlockTime))
	{
		return pdTRUE;
	}
	else
	{
		return pdFALSE;
	}
}
/*-----------------------------------------------------------*/

void vSerialPutString(xComPortHandle pxPort, const signed char *const pcString, unsigned short usStringLength)
{
	signed char *pxNext;

	/* A couple of parameters that this port does not use. */
	(void)usStringLength;
	(void)pxPort;

	/* NOTE: This implementation does not handle the queue being full as no
	block time is used! */

	/* The port handle is not required as this driver only supports UART1. */
	(void)pxPort;

	/* Send each character in the string, one at a time. */
	pxNext = (signed char *)pcString;
	while (*pxNext)
	{
		xSerialPutChar(pxPort, *pxNext, serNO_BLOCK);
		pxNext++;
	}
}
/*-----------------------------------------------------------*/

signed portBASE_TYPE xSerialPutChar(xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime)
{
	signed portBASE_TYPE xReturn;
	if (xQueueSend(xCharsForTx, &cOutChar, xBlockTime) == pdPASS)
	{
		xReturn = pdPASS;
		uint8_t cChar;
		if (xQueueReceive(xCharsForTx, &cChar, 0) == pdTRUE)
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */
			while(HAL_UART_Transmit_IT(&huart1, &cChar, 1) != HAL_OK);
		}
	}
	else
	{
		xReturn = pdFAIL;
	}

	return xReturn;
}
/*-----------------------------------------------------------*/

void vSerialClose(xComPortHandle xPort)
{
	/* Not supported as not required by the demo application. */
}
/*-----------------------------------------------------------*/

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART1)
	{
		portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
		xQueueSendFromISR(xRxedChars, &aRxBuffer, &xHigherPriorityTaskWoken);
		HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1);
	}
}
